6.11 Bash POSIX 模式(Bash POSIX Mode)

在带有“—posix”选项启动 Bash 后,或在 Bash 已运行时执行“set -o posix”命令,都会改变 Bash 的默认行为,使其更接近于 POSIX 规范来运行。

当使用 sh 调用 Bash 时,在读取了启动文件之后其会进入 POSIX 模式。

下面的列表列出了在 POSIX 模式生效后的变化:

  1. Bash 确保设置了变量 POSIXLY_CORRECT。
  2. 当在哈希表中的一个命令不存在了,Bash 会重新搜索“$PATH”来寻找其新的位置。也可以使用“shopt -s checkhash”设置。
  3. Bash 不会将一个没有设置执行位的命令插入到命令哈希表中,即使其是从“$PATH”搜索(最后的手段)中返回得来的结果。
  4. 当一个作业退出是“Done(status)”时带有非零状态,作业控制代码或内建命令会打印消息。
  5. 当一个作业停止时是“Stopped(signame)”,“signame”例如是 SIGTSTP,作业控制代码或内建命令会打印消息。
  6. 别名扩展总是处于开启状态,即使是处于非交互式 shell 中。
  7. 保留字出现在能够识别保留字的上下文中时是不会进行别名扩展的。
  8. 开启了 POSIX 变量 PS1 和 PS2 扩展中的由“!”到历史编号和由“!!”到“!”的扩展。并且在 PS1 和 PS2 的值上执行的参数扩展与“promptvars”选项设置无关。
  9. 执行 POSIX 启动文件($ENV)而不是普通 Bash 文件。
  10. 波浪号扩展只执行于命令名之前的赋值语句,而不是在这一行中的所有赋值语句中。
  11. 默认历史文件是“~/.sh_history”(这是$HISTFILE 的默认值)。
  12. 除非 shell 是交互式的,否则重定向操作符不会在重定向中的单词上执行文件名扩展。
  13. 重定向操作符不会在重定向中的单词上执行单词分割。
  14. 函数名必须是有效的 shell 名称。就是说,其不能包括除了字母、数字和下划线之外的字符,并且不能由数字开头。在非交互式 shell 中声明一个无效名称的函数,会引起致命的语法错误。
  15. 函数名不能与 POSIX 特殊内建命令名相同。
  16. 在命令查找期间,会在查找 shell 函数之前先查找 POSIX 特殊内建命令。
  17. 在打印 shell 函数定义时(例如使用 type 命令),Bash 不会打印关键字“function”。
  18. 出现在变量 PATH 元素中作为第一个字符的波浪符号不会像在 3.5.2《波浪号扩展》中描述的那样进行扩展。
  19. 保留字“time”其自身可以作为一个命令使用。当使用这种方式时,其会显示 shell 及其子 shell 的时间统计信息。变量 TIMEFORMAT 用于控制时间信息的格式。
  20. 当解析和扩展在双引号中出现的“${…}”时,单引号不再有特殊含义,并且不能用于引用后半个大括号或其它特殊字符,除非操作符是用于执行样式移除的这些定义之一。若是这样,它们不会作为匹配对出现。
  21. 如果下一个标记由“-”开头,解析器不会认为其前面的 time 是一个保留字。
  22. 即使“histexpand”选项开启了,在双引号字符串中的“!”字符也不会引用为历史扩展。
  23. 如果 POSIX 的特殊内建命令返回一个错误状态,则非交互 shell 会退出。重大错误列出在 POSIX 标准中,并且包括一些像传入非正确选项、重定向错误、在命令名之前的赋值语句中变量赋值错误等等。
  24. 如果在赋值语句后面没有跟随命令名的情况下变量赋值报错了,则非交互式 shell 会返回报错状态并退出。例如,当试图给一个只读变量赋值时,就会出现变量赋值错误。
  25. 如果一个变量赋值错误出现在特殊内建命令(而不是任何其它简单命令)前面的赋值语句中,非交互式 shell 会返回错误状态并退出。
  26. 如果在 for 语句中的迭代变量或在 select 语句中的选择变量是只读变量,非交互式 shell 会返回错误状态并退出。
  27. 在“. filename”中的“filename”没有找到,非交互式 shell 会退出。
  28. 如果算术表达式中的语法错误导致了表达式无效,非交互式 shell 会退出。
  29. 如果参数扩展报错,非交互式 shell 会退出。
  30. 如果在使用“.”或“source”内建命令读取的脚本中,或在 eval 内建命令处理的字符串中有语法错误,非交互式 shell 会退出。
  31. 在间接变量可用期间,其不可以应用到特殊参数“#”和“?”。
  32. 当在样式上下文中的特殊参数“*”的扩展是在双引号里的时候,不会像“$*”在双引号里一样处理。
  33. 在 POSIX 特殊内建命令前面的赋值语句,在内建命令完成之后会存留于 shell 环境中。
  34. 内建命令 command 不会阻止拿赋值语句作为参数的内建命令扩展为赋值语句;当不在 POSIX 模式时,command 命令后面的赋值内建命令会失去其赋值语句扩展属性。
  35. 内建命令 bg 使用必要的格式来描述每一个后台作业,但不会指出该作业是当前的还是上一个。
  36. 使用“kill -l”在一行里使用空格作为分隔符,打印出所有的信号名。信号名是不带有 SIG 前缀的。
  37. 内建命令 kill 不接受带有 SIG 前缀的信号名。
  38. 内建命令 export 和 readonly 按 POSIX 要求格式显示它们的输出。
  39. 内建命令 trap 显示的信号名是不带有 SIG 前缀的。
  40. 除非内建命令 trap 的第一个参数是由单一数字组成并且是一个有效的信号编号,否则其不会对第一个参数进行可行信号规范检查并且不会将信号处理句柄恢复到初始配置。如果用户想要为给定信号重置处理句柄为初始配置,则第一个参数应该使用“-”。
  41. “trap -p”显示配置为 SIG_DFL 的信号,并且在 shell 启动时忽略这些信号。
  42. 如果“.”和“source”命令在 PATH 搜索中没有找到文件名参数,其不会对当前目录进行搜索。
  43. 开启 POSIX 模式是会对“inherit_errexit”选项设置产生影响。其影响是所产生用于执行命令替换的子 shell 会从父 shell 继承“-e”选项的值。当“inherit_errexit”选项没有开启时,Bash 会在子 shell 中清除“-e”选项。
  44. 开启 POSIX 模式是会对“shift_verbose”选项设置产生影响。其影响是 shift 命令的数字参数如果超过了位置参数的个数,则会产生报错消息。
  45. 当内建命令 alias 显示别名定义时,除非给出了“-p”选项,否则其不会显示前导词“alias”。
  46. 当调用内建命令 set 时不带有选项,其不会显示 shell 函数名和其定义。
  47. 当调用内建命令 set 时不带有选项,即使显示结果包含非打印字符,其显示的变量值是不会带有引号的,除非其中包含了 shell 元字符。
  48. 当在逻辑模式中调用内建命令 cd 时,路径名是由$PWD 构建的,并且作为参数所提供的目录名没有引用到一个已存在的目录,cd 将会失败而不是回退到物理模式。
  49. 当因为从$PWD 中构建的路径名长度和当所有软链接扩展后作为参数提供的目录名超出了PATH_MAX,而引起内建命令 cd 而不能改变目录时,该命令会失败,而不是试图只使用提供的目录名。
  50. 内建命令 pwd 验证其打印的值和当前目录是否相同,即使没有使用“-P”选项来检查文件系统。
  51. 当列出历史命令时,内建命令 fc 不会包含历史条目是否被修改的指示。
  52. fc 的默认编辑器是 ed。
  53. 尽管在$PATH 中找到的不可执行的文件 shell 会试图执行,内建命令 type 和 command 都不会报告其找到的是一个不可执行的文件。
  54. 当命令“v”运行时,vi 编辑模式会直接调用 vi 编辑器,而不是检查变量$VISUAL和$EDITOR。
  55. 当“xpg_echo”选项开启后,Bash 不会试图将 echo 命令的任何参数翻译为选项。在转义字符转义之后会显示每一个参数。
  56. 内建命令 ulimit 会为“-c”和“-f”选项使用 512 字节的块大小。
  57. 当捕获器设置了 SIGHLD 信号,该信号到达时不会中断内建命令 wait 并使其立即返回。每个子结点退出时都会运行一次 trap 命令。
  58. 内建命令 read 可以被捕获器设置的信号中断。在执行 read 期间如果 Bash 收到了捕获的信号,捕获句柄会执行并且 read 命令会退出并返回一个大于 128 的状态。
  59. 在内建命令 wait 获取到已退出的后台进程状态之后,Bash 将其从状态列表中移除。

即使是在 POSIX 模式下,这有一些其它的 POSIX 行为在默认情况下 Bash 是不会执行的。特别是:

  1. 如果变量 FCEDIT 未设置或已释放,内建命令 fc 会检查$EDITOR 来作为编辑历史条目的程序,而不是直接使用默认值 ed。如果变量 EDITOR 未设置或已释放,则使用 ed。
  2. 就像在上面提到的,为了使内建命令 echo 达到完全一致,Bash 需要开启 xpg_echo 选项。

在构建 Bash 时指定选项“—enable-strict-posix-default”,可将 Bash 默认配置为符合 POSIX 模式(参见 10.8《可选特性》)。